#ifndef X86_H
#define X86_H

#include "crossbit/common.h"
#include "crossbit/VInst.h"
#include <assert.h>
#include <iostream>
#include <string>

namespace crossbit {

    class X86 {
	public:

	    /* Encoding of Conditional Test (tttn) Field */
	    static const unsigned char EQ = 0x4;	    /* 0100 */
	    static const unsigned char NE = 0x5;	    /* 0101 */
	    static const unsigned char NA = 0x6;	    /* 0110 */
	    static const unsigned char GT = 0xf;	    /* 1111 */
	    static const unsigned char GE = 0xd;	    /* 1101 */
	    static const unsigned char LT = 0xc;	    /* 1100 */ 
	    static const unsigned char LE = 0xe;	    /* 1110 */
	    static const unsigned char AB = 0x7;	    /* 0111 */
	    static const unsigned char BE = 0x2;	    /* 0010 */

	    static const unsigned char CCENCODINGS[9];
	    static const unsigned char ANTICCENCODINGS[8];

	    /* Encoding of General-purpose register field */
	    static const RegNum EAX = 0;
	    static const RegNum ECX = 1;
	    static const RegNum EDX = 2;
	    static const RegNum EBX = 3;
	    static const RegNum ESP = 4;
	    static const RegNum EBP = 5;
	    static const RegNum ESI = 6;
	    static const RegNum EDI = 7;

	    static const std::string REG2STR[8];

	    static inline void setP(char *p)
	    {
		p_ = p;
	    }

	    static inline char *getP()
	    {
		return p_;
	    }

	    static void word(Word word)
	    {
		*((Word *)p_) = word;
		p_ += 4;
	    }

	    //added by zhengjuyu
	    static inline void nop()
	    {
		*p_++ = 0x90;
	    }

	    static inline void inc(RegNum reg)
	    {
		*p_++ = 0x40 | reg;
	    }

	    static inline void dec(RegNum reg)
	    {
		*p_++ = 0x48 | reg;
	    }

	    // 01 /r	ADD r/m32, r32	    Add r32 to r/m32
	    /* 0000 000w : 11 reg1 reg2 */
	    static inline void add_reg_to_reg(RegNum reg1, RegNum reg2)
	    {   
		*p_++ = 0x01;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 0000 000w : mod reg r/m : disp32*/
	    static inline void add_reg_to_mem(RegNum reg, MemAddr mem)
	    {
		*p_++ = 0x01;
		*p_++ = (reg << 3) | 0x05; /* mod:00 reg r/m:101 */
		word(mem);
	    }

	    /* 1000 00sw : 11 000 reg : immediate data  */
	    static inline void add_imm_to_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xc0 | reg;
		word(imm);
	    }

	    static inline void add_imm8_to_reg(Byte imm, RegNum reg)
	    {
		*p_++ = 0x83;
		*p_++ = 0xc0 | reg;
		*p_++ = imm;
	    }

	    /* 0010 000w : 11 reg1 reg2 */
	    static inline void and_reg_to_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x21;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 1000 00sw : 11 100 reg : immediate data */
	    static inline void and_imm_to_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xe0 | reg;
		word(imm);
	    }

	    /* 0011 000w : 11 reg1 reg2 */
	    static inline void xor_reg_to_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x31;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 1000 00sw : 11 110 reg : immediate data */
	    static inline void xor_imm_to_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xf0 | reg;
		word(imm);
	    }

	    /* 0000 100w : 11 reg1 reg2 */
	    static inline void or_reg_to_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x09;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 1000 00sw : 11 001 reg : immediate data */
	    static inline void or_imm_to_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xc8 | reg;
		word(imm);
	    }

	    /* 0010 100w : 11 reg1 reg2 */
	    static inline void sub_reg_from_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x29;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 1000 000w : 11 101 reg : immediate data */
	    static inline void sub_imm_from_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xe8 | reg;
		word(imm);
	    }

	    /* 1000 000w : 11 101 reg : immediate data  */
	    static inline void sub_imm8_from_reg(Byte imm, RegNum reg)
	    {
		*p_++ = 0x80;
		*p_++ = 0xe8 | reg;
		*p_++ = imm;
	    }

	    /* 1111 011w : 11 010 reg */
	    static inline void not_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xd0 | reg;
	    }
	    
	    /* 1111 011w : 11 011 reg */
	    static inline void neg_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xd8 | reg;
	    }

	    /* 1100 000w : 11 100 reg : imm8 data */
	    static inline void shl_reg_by_imm(RegNum reg, unsigned char imm)
	    {
		*p_++ = 0xc1;
		*p_++ = 0xe0 | reg;
		*((unsigned char *)p_++) = imm;
	    }

	    /* 1101 001w : 11 100 reg */
	    static inline void shl_reg_by_cl(RegNum reg)
	    {
		*p_++ = 0xd3;
		*p_++ = 0xe0 | reg;
	    }

	    /* 1100 000w : 11 111 reg : imm8 data */
	    static inline void sar_reg_by_imm(RegNum reg, unsigned char imm)
	    {
		*p_++ = 0xc1;
		*p_++ = 0xf8 | reg;
		*((unsigned char *)p_++) = imm;
	    }

	    /* 1101 001w : 11 111 reg */
	    static inline void sar_reg_by_cl(RegNum reg)
	    {
		*p_++ = 0xd3;
		*p_++ = 0xf8 | reg;
	    }

	    /* 1100 000w : 11 101 reg : imm8 data */
	    static inline void shr_reg_by_imm(RegNum reg, unsigned char imm)
	    {
		*p_++ = 0xc1;
		*p_++ = 0xe8 | reg;
		*((unsigned char *)p_++) = imm;
	    }

	    /* 1101 001w : 11 101 reg */
	    static inline void shr_reg_by_cl(RegNum reg)
	    {
		*p_++ = 0xd3;
		*p_++ = 0xe8 | reg;
	    }

	    /* 1111 011w : 11 101 reg */
	    static inline void imul_eax_to_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xe8 | reg;
	    }

	    /* 1111 011w : 11 100 reg */
	    static inline void mul_eax_to_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xe0 | reg;
	    }

	    /* 1111 011w : 11 111 reg */
	    static inline void idiv_edx_eax_by_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xf8 | reg;
	    }

	    /* 111 011w : 11 110 reg */
	    static inline void div_edx_eax_by_reg(RegNum reg)
	    {
		*p_++ = 0xf7;
		*p_++ = 0xf0 | reg;
	    }

	    /* 1100 011w : 11 000 reg : immediate data */
	    static inline void movw_imm_to_reg(Word imm, RegNum reg)
	    {
		*p_++ = 0xc7; /* 1100 011w, w = 1 */
		*p_++ = 0xc0 | reg;
		word(imm);
	    }


            static inline void mov_imm_to_mem(Word imm, MemAddr mem, BlockSize size)
            {
                  switch(size)
                  {
		      case BYTE: movb_imm_to_mem(imm, mem); break;
		      case HALFWORD: movh_imm_to_mem(imm, mem); break;
		      case WORD: movw_imm_to_mem(imm, mem); break;
                  }
 
            }

	    static inline void movb_imm_to_mem(Word imm, MemAddr mem)
	    {
		*p_++ = 0xc6;
		*p_++ = 0x5;
		word(mem);
		*p_++ = (char)imm;
	    }
	    
	    static inline void movh_imm_to_mem(Word imm, MemAddr mem)
	    {
		*p_++ = 0x66;
		*p_++ = 0xc7;
		*p_++ = 0x5;
		word(mem);
	        *((unsigned short*)(p_)) = (unsigned short)imm;
                 p_ += 2;
	    }
	    
	    /* 1100 011w : mod 000 r/m : immediate data*/
	    static inline void movw_imm_to_mem(Word imm, MemAddr mem)
	    {
		*p_++ = 0xc7;
		*p_++ = 0x5; /* mod:00 000 r/m:101 */
		word(mem);
		word(imm);
	    }

            static inline void mov_imm_to_mem(Word imm, RegNum reg, Word disp, BlockSize size)
            {
		switch(size)
		{
		    case WORD: movw_imm_to_mem(imm, reg, disp);break;
	            case HALFWORD: movh_imm_to_mem(imm, reg, disp);break;
		    case BYTE: movb_imm_to_mem(imm, reg, disp);break;
		}
            }

	    static inline void movb_imm_to_mem(Word imm, RegNum reg, Word disp)
	    {
		*p_++ = 0xc6;
		*p_++ = 0x80 | reg;
		word(disp);
		*p_++ = (char)imm;
	    }
	    
	    static inline void movh_imm_to_mem(Word imm, RegNum reg, Word disp)
	    {
		*p_++ = 0x66;
		*p_++ = 0xc7;
		*p_++ = 0x80 | reg;
		word(disp);
		*((unsigned short*)(p_)) = (unsigned short)imm;
                p_ += 2;
	    }
	    
	    /* 1100 011w : mod 000 r/m : immediate data*/
	    static inline void movw_imm_to_mem(Word imm, RegNum reg, Word disp)
	    {
		*p_++ = 0xc7;
		*p_++ = 0x80 | reg; /* mod:10 000 r/m:reg */
		word(disp);
		word(imm);
	    }

	    static inline void mov_mem_to_reg(MemAddr mem, BlockSize size, RegNum dst)
	    {
		switch (size) {
		    case WORD:	    movw_mem_to_reg(mem, dst); break;
		    case HALFWORD:  movh_mem_to_reg(mem, dst); break;
		    case BYTE:	    movb_mem_to_reg(mem, dst); break;
		}
	    }

	    /* 1000 1011 : mod reg r/m  */
	    static inline void movw_mem_to_reg(MemAddr mem, RegNum dst)
	    {
		*p_++ = 0x8b;    /* 1000 1011 */
		*p_++ = dst << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		word(mem);
	    }

	    /* 1000 1010 : mod reg r/m  */
	    static inline void movb_mem_to_reg(MemAddr mem, RegNum dst)
	    {
		*p_++ = 0x8a;    /* 1000 1011 */
		*p_++ = dst << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		*((unsigned int *)p_) = (unsigned int)mem;	/* disp_32 */
		p_ += 4;
	    }

	    /* prefix:0x66 1000 1011 : mod reg r/m  */
	    static inline void movh_mem_to_reg(MemAddr mem, RegNum dst)
	    {
		*p_++ = 0x66;
		*p_++ = 0x8b;    /* 1000 1011 */
		*p_++ = dst << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		*((unsigned int *)p_) = (unsigned int)mem;	/* disp_32 */
		p_ += 4;
	    }

	    static inline void mov_mem_to_reg(RegNum reg, Word disp, BlockSize size, RegNum dst)
	    {
		switch (size) {
		    case WORD:		movw_mem_to_reg(reg, disp, dst); break;
		    case HALFWORD:	movh_mem_to_reg(reg, disp, dst); break;
		    case BYTE:		movb_mem_to_reg(reg, disp, dst); break;
		}
	    }

	    /* 1000 1011 : mod reg r/m  */
	    static inline void movw_mem_to_reg(RegNum reg, Word disp, RegNum dst)
	    {
		assert(reg != ESP);
		*p_++ = 0x8b;
		*p_++ = 0x80 | (dst << 3) | reg;    /* mod:10, dst, r/m:reg */
		*((Word *)p_) =  disp;
		p_ += 4;
	    }

	    /* 1000 1010 : mod reg r/m  */
	    static inline void movb_mem_to_reg(RegNum reg, Word disp, RegNum dst)
	    {
		assert(reg != ESP);
		*p_++ = 0x8a;
		*p_++ = 0x80 | (dst << 3) | reg;    /* mod:10, dst, r/m:reg */
		*((Word *)p_) =  disp;
		p_ += 4;
	    }

	    /* prefix:0x66 1000 1011 : mod reg r/m  */
	    static inline void movh_mem_to_reg(RegNum reg, Word disp, RegNum dst)
	    {
		assert(reg != ESP);
		*p_++ = 0x66;
		*p_++ = 0x8b;
		*p_++ = 0x80 | (dst << 3) | reg;    /* mod:10, dst, r/m:reg */
		*((Word *)p_) =  disp;
		p_ += 4;
	    }

    
	    static inline void mov_mem_to_reg(RegNum src, BlockSize size, RegNum dst)
	    {
		switch (size) {
		    case WORD:		movw_mem_to_reg(src, dst); break;
		    case HALFWORD:	movh_mem_to_reg(src, dst); break;
		    case BYTE:		movb_mem_to_reg(src, dst); break;
		}
	    }

	    /* 1000 1011 : mod dst r/m */
	    static inline void movw_mem_to_reg(RegNum src, RegNum dst)
	    {
		assert(src != ESP && src != EBP);
		*p_++ = 0x8b;
		*p_++ = (dst << 3) | src; /* mod:00 dst r/m:src */
	    }

	    /* 1000 1010 : mod dst r/m */
	    static inline void movb_mem_to_reg(RegNum src, RegNum dst)
	    {
		assert(src != ESP && src != EBP);
		*p_++ = 0x8a;
		*p_++ = (dst << 3) | src; /* mod:00 dst r/m:src */
	    }

	    /* prefix:0x66 1000 1011 : mod dst r/m */
	    static inline void movh_mem_to_reg(RegNum src, RegNum dst)
	    {
		assert(src != ESP && src != EBP);
		*p_++ = 0x66;
		*p_++ = 0x8b;
		*p_++ = (dst << 3) | src; /* mod:00 dst r/m:src */
	    }

	    static inline void mov_reg_to_mem(RegNum reg, BlockSize size, MemAddr addr)
	    {
		switch (size) {
		    case WORD:		movw_reg_to_mem(reg, addr); break;
		    case HALFWORD:	movh_reg_to_mem(reg, addr); break;
		    case BYTE:		movb_reg_to_mem(reg, addr); break;
		}
	    }

	    /* 1000 1001 : mod reg r/m */
	    static inline void movw_reg_to_mem(RegNum reg, MemAddr addr)
	    {
		*p_++ = 0x89;    /* 1000 1001 */
		*p_++ = reg << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		*((unsigned int *)p_) = (unsigned int)addr;	/* disp_32 */
		p_ += 4;
	    }

	    /* 1000 1000 : mod reg r/m */
	    static inline void movb_reg_to_mem(RegNum reg, MemAddr addr)
	    {
		*p_++ = 0x88;    /* 1000 1001 */
		*p_++ = reg << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		*((unsigned int *)p_) = (unsigned int)addr;	/* disp_32 */
		p_ += 4;
	    }

	    /* prefix:0x66 1000 1001 : mod reg r/m */
	    static inline void movh_reg_to_mem(RegNum reg, MemAddr addr)
	    {
		*p_++ = 0x66;
		*p_++ = 0x89;    /* 1000 1001 */
		*p_++ = reg << 3 | 0x5;  /* mod:00, reg, r/m:101 */
		*((unsigned int *)p_) = (unsigned int)addr;	/* disp_32 */
		p_ += 4;
	    }


	    static inline void mov_reg_to_mem(RegNum src, BlockSize size, RegNum reg, Word disp)
	    {
		switch (size) {
		    case WORD:		movw_reg_to_mem(src, reg, disp); break;
		    case HALFWORD:	movh_reg_to_mem(src, reg, disp); break;
		    case BYTE:		movb_reg_to_mem(src, reg, disp); break;
		}
	    }

	    /* 1000 1001 : mod reg r/m */
	    static inline void movw_reg_to_mem(RegNum src, RegNum reg, Word disp)
	    {
		assert(reg != ESP);
		*p_++ = 0x89;
		*p_++ = 0x80 | (src << 3) | reg;
		*((Word *)p_) = disp;
		p_ += 4;
	    }

	    /* 1000 1000 : mod reg r/m */
	    static inline void movb_reg_to_mem(RegNum src, RegNum reg, Word disp)
	    {
		assert(reg != ESP);
		*p_++ = 0x88;
		*p_++ = 0x80 | (src << 3) | reg;
		*((Word *)p_) = disp;
		p_ += 4;
	    }

	    /* 1000 1001 : mod reg r/m */
	    static inline void movh_reg_to_mem(RegNum src, RegNum reg, Word disp)
	    {
		assert(reg != ESP);
		*p_++ = 0x66;
		*p_++ = 0x89;
		*p_++ = 0x80 | (src << 3) | reg;
		*((Word *)p_) = disp;
		p_ += 4;
	    }



	    static inline void mov_reg_to_mem(RegNum src, BlockSize size, RegNum dst)
	    {
		switch (size) {
		    case WORD:		movw_reg_to_mem(src, dst);
		    case HALFWORD:	movh_reg_to_mem(src, dst);
		    case BYTE:		movb_reg_to_mem(src, dst);
		}
	    }

	    /* 1000 1001 : mod src r/m */
	    static inline void movw_reg_to_mem(RegNum src, RegNum dst)
	    {
		assert(dst != ESP && dst != EBP);
		*p_++ = 0x89;
		*p_++ = (src << 3) | dst;
	    }

	    /* 1000 1000 : mod src r/m */
	    static inline void movb_reg_to_mem(RegNum src, RegNum dst)
	    {
		assert(dst != ESP && dst != EBP);
		*p_++ = 0x88;
		*p_++ = (src << 3) | dst;
	    }

	    /* prefix:0x66 1000 1001 : mod src r/m */
	    static inline void movh_reg_to_mem(RegNum src, RegNum dst)
	    {
		assert(dst != ESP && dst != EBP);
		*p_++ = 0x66;
		*p_++ = 0x89;
		*p_++ = (src << 3) | dst;
	    }

	    /* 1000 101w : 11 dst src */
	    static inline void movw_reg_to_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x8b;   /* 1000 1011 */ 
		*p_++ = 0xc0 | (reg2 << 3) | reg1;	/* 11 reg1 reg2 */
	    }

	    /* 0000 1111 : 1011 1110 : 11 dst src */
	    static inline void movsbl_reg_to_reg(RegNum src, RegNum dst)
	    {
		*p_++ = 0x0f;
		*p_++ = 0xbe;
		*p_++ = 0xc0 | (dst << 3) | src;
	    }

	    /* 0000 1111 : 1011 1111 : 11 dst src */
	    static inline void movswl_reg_to_reg(RegNum src, RegNum dst)
	    {
		*p_++ = 0x0f;
		*p_++ = 0xbf;
		*p_++ = 0xc0 | (dst << 3) | src;
	    }

	    /* 0000 1111 : 1011 0110 : 11 dst src */
	    static inline void movzbl_reg_to_reg(RegNum src, RegNum dst)
	    {
		*p_++ = 0x0f;
		*p_++ = 0xb6;
		*p_++ = 0xc0 | (dst << 3) | src;
	    }

	    /* 0000 1111 : 1011 0111 : 11 dst src */
	    static inline void movzwl_reg_to_reg(RegNum src, RegNum dst)
	    {
		*p_++ = 0x0f;
		*p_++ = 0xb7;
		*p_++ = 0xc0 | (dst << 3) | src;
	    }

	    /* 1100 0011 */
	    static inline void ret()
	    {
		*p_++ = 0xc3;
	    }

	    /* 0011 100w : 11 reg2 reg1 */
	    static inline void cmp_reg_with_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x39;
		*p_++ = 0xc0 | (reg2 << 3) | reg1;
	    }


	    /* 1000 0001 : 11 111 reg : immediate data */
	    static inline void cmp_imm_with_reg(int imm, RegNum reg)
	    {
		*p_++ = 0x81;
		*p_++ = 0xf8 | reg;
		word(imm);
	    }

	    static inline void fcmp_fpreg_with_fpreg_pop()
	    {
		*p_++ = 0xdf;
		*p_++ = 0xf1;
	    }

	    /* 1000 0101 : 11 reg1 reg2 */
	    static inline void test_reg_with_reg(RegNum reg1, RegNum reg2)
	    {
		*p_++ = 0x85;
		*p_++ = 0xc0 | (reg1 << 3) | reg2;
	    }

	    /* 0000 1111 : 1001 tttn : 11 000 reg */
	    static inline void setcc(RegNum reg, unsigned char tttn)
	    {
		*p_++ = 0x0f;
		*p_++ = 0x90 | tttn;
		*p_++ = 0xc0 | reg;
	    }

	    static inline void jecxz(Byte disp)
	    {
		*p_++ = 0xe3;
		*p_++ = disp;
	    }

	    /* 1111 1111 : mod 100 r/m */
	    static inline void jmp_absolute_indirect_memory(MemAddr addr)
	    {
		*p_++ = 0xff;
		*p_++ = /* 00 100 101 */ 0x25;
		*((unsigned int *)p_) = addr;
		p_ += 4;
	    }

	    /* 1111 1111 : 1110 0 reg*/
	    static inline void jmp_absolute_indirect_reg(RegNum reg)
	    {
		*p_++ = 0xff;
		*p_++ = 0xe0 | reg;
	    }

	    /* 1110 1001 : full displacement */
	    static inline void jmp_relative_direct_disp32(int disp)
	    {
		*p_++ = 0xe9;
		word(disp);
	    }
	    
	    /* 0000 1111 : 1000 tttn : full displacement */
	    static inline void jcc_relative_direct_disp32(int disp, unsigned char tttn)
	    {
		*p_++ = 0x0f;
		*p_++ = 0x80 | tttn;
		word(disp);
	    }

	    /* 0000 1111 : 1000 0100 : full displacement */
	    static inline void je_relative_direct_disp32(int disp)
	    {
		*p_++ = 0x0f;
		*p_++ = 0x84;
		word(disp);
	    }

	    static inline void jne_relative_direct_disp32(int disp)
	    {
		*p_++ = 0x0f;
		*p_++ = 0x85;
		word(disp);
	    }

	    // 1110 1000 : displacement32
	    static inline void call_relative_direct_disp32(int disp)
	    {
		*p_++ = 0xe8;
		word(disp);
	    }

	    // 0110 1000 : imm32
	    static inline void push_imm32(Word imm32)
	    {
		*p_++ = 0x68;
		word(imm32);
	    }

	    // 0x60
	    static inline void push_all()
	    {
		*p_++ = 0x60;
	    }

	    // 0101 0 reg
	    static inline void push_reg(RegNum reg)
	    {
		*p_++ = 0x50 | reg;
	    }

	    // 0101 1 reg
	    static inline void pop_reg(RegNum reg)
	    {
		*p_++ = 0x58 | reg;
	    }

	    // 0x61
	    static inline void pop_all() 
	    {
		*p_++ = 0x61;
	    }
	
	    // float-point instruction
    	    
	    //0xd9	,flds 32bit
	    static inline void fp_push_freg32(MemAddr addr)
	    {
		*p_++ = 0xd9;
		*p_++ = 0x05;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void fp_push_freg32_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xd9;
		*p_++ = 0x80 | reg;
		word(disp);
	    }
 	    //0xdd	,fldl 64bit
	    static inline void fp_push_freg64(MemAddr addr)
	    {
		*p_++ = 0xdd;
		*p_++ = 0x05;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void fp_push_freg64_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdd;
		*p_++ = 0x80 | reg;
		word(disp);
	    }

	    //0xdf	,fild addr
	    static inline void int_push_freg16(MemAddr addr)
	    {
		*p_++ = 0xdf;
		*p_++ = 0x05;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void int_push_freg16_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdf;
		*p_++ = 0x80 | reg; 
		word(disp);
	    }

	    //0xdb	,fildl addr
	    static inline void int_push_freg32(MemAddr addr)
	    {
		*p_++ = 0xdb;
		*p_++ = 0x05;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void int_push_freg32_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdb;
		*p_++ = 0x80 | reg; 
		word(disp);
	    }
	
	    //0xdf	,fildll addr
	    static inline void longlong_push_freg64(MemAddr addr)
	    {
		*p_++ = 0xdf;
		*p_++ = 0x2d;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    //0xdf	,fildll addr
	    static inline void longlong_push_freg64_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdf;
		*p_++ = 0xa8 | reg; 
		word(disp);
	    }

	    //0xd9	,fstps 32bit
	    static inline void fp_pop_freg32(MemAddr addr)
	    {
		*p_++ = 0xd9;
		*p_++ = 0x1d;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }
	    
	    static inline void fp_pop_freg32_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xd9;
		*p_++ = 0x98 | reg;
		word(disp);
	    }

	    //0xdd	,fstpl 64bit
	    static inline void fp_pop_freg64(MemAddr addr)
	    {
		*p_++ = 0xdd;
		*p_++ = 0x1d;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }
	    
	    static inline void fp_pop_freg64_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdd;
		*p_++ = 0x98 | reg;
		word(disp);
	    }

	    //0xdb	,fistpl 32bit   
	    static inline void int_pop_freg32(MemAddr addr)
	    {
		*p_++ = 0xdb;
		*p_++ = 0x1d;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void int_pop_freg32_base_disp(RegNum reg, Word disp)
	    {
		*p_++ = 0xdb;
		*p_++ = 0x98 | reg; 
		word(disp);
	    }

	    //0xdb	,fistpll 64bit
	    static inline void longlong_pop_freg64(MemAddr addr)
	    {
		*p_++ = 0xdf;
		*p_++ = 0x3d;
		*(MemAddr *)p_ = addr;
		p_+=4;
	    }

	    static inline void longlong_pop_freg64_base_disp (RegNum reg, Word disp)
	    {
		*p_++ = 0xdf;
		*p_++ = 0xb8 | reg;
		word(disp);
	    }

	    //0xde	,FADDP1 32bit
   	    static inline void fp_add32()
	    {
		*p_++ = 0xde;
		*p_++ = 0xc1;
	    }

	    //0xde	,FADDP1 64bit
   	    static inline void fp_add64()
	    {
		*p_++ = 0xde;
		*p_++ = 0xc1;
	    }

	    //0xd8	,FSUBP1 32bit
	    //ST(1)<-ST(1)-ST(0)
	    //pop ST(0)
	    static inline void fp_sub32()
	    {
		*p_++ = 0xde;
		*p_++ = 0xe9;
	    }

	    //0xd8	,FSUBP1 64bit
	    //ST(1)<-ST(1)-ST(0)
	    //pop ST(0)
	    static inline void fp_sub64()
	    {
		*p_++ = 0xde;
		*p_++ = 0xe9;
	    }
	    // 0xde	,FMULTP 32/64
   	    static inline void fp_mult32()
	    {
		*p_++ = 0xde;
		*p_++ = 0xc9;
	    }

	    // 0xde	,FMULTP 32/64
   	    static inline void fp_mult64()
	    {
		*p_++ = 0xde;
		*p_++ = 0xc9;
	    }
	    
	    // 0x	,FDIVP  32/64
   	    static inline void fp_div32()
	    {
		*p_++ = 0xde;
		*p_++ = 0xf9;
	    }

   	    static inline void fp_div64()
	    {
		*p_++ = 0xde;
		*p_++ = 0xf9;
	    }

	    static inline void fp_chs()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xe0;
	    }

	    static inline void fp_sqrt()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xfa;
	    }

	    static inline void fabs()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xe1;
	    }
	    
	    static inline void fldcw( MemAddr addr )
	    {*p_++ = 0xdb; *p_++=0xe2;
		*p_++ = 0xd9;
		*p_++ = 0x2d;
		word(addr);
	    }

	    static inline void fstcw( MemAddr addr )
	    {
		*p_++ = 0xd9;
		*p_++ = 0x3d;
		word(addr);
	    }

	    static inline void fnstsw()
	    {
		*p_++ = 0xdf;
		*p_++ = 0xe0;
	    }

	    static inline void fincstp()
	    {
		*p_++ = 0xdd;
		*p_++ = 0xc0;
		*p_++ = 0xd9;
		*p_++ = 0xf7;
	    }

	    static inline void fp_frndint()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xfc;
	    }

	    static inline void fp_fchs()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xe0;
	    }

	    static inline void fp_fxam()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xe5;
	    }

	    static inline void fp_fldlg2()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xec;
	    }

	    static inline void fp_fldln2()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xed;
	    }

	    static inline void fp_fldl2e()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xea;
	    }

	    static inline void fp_fyl2x()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xf1;
	    }

	    static inline void fp_fyl2xp1()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xf9;
	    }

	    static inline void fp_f2xm1()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xf0;
	    }

	    static inline void fp_fscale()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xfd;
	    }

	    static inline void fp_fcos()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xff;
	    }

	    static inline void fp_fsin()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xfe;
	    }

	    static inline void fp_fptan()
	    {
		*p_++ = 0xd9;
		*p_++ = 0xf2;
	    }

	    //0xcc
	    //Added by Zheng Juyu, for single break
	    static inline void sbreak()
	    {
	        *p_++ = 0xcc;
	    }

	    // 0x0f bc
	    // bsf
	    static inline void bsf(RegNum src, RegNum dst)
	    {
	        *p_++ = 0x0f;
		*p_++ = 0xbc;
		*p_++ = 0xc0 | dst << 3 | src; 
	    }

	    // 0x0f bd
	    // bsr
	    static inline void bsr(RegNum src, RegNum dst)
	    {
	        *p_++ = 0x0f;
		*p_++ = 0xbd;
		*p_++ = 0xc0 | dst << 3 | src; 
	    }

	private:
	    static char *p_;

	    static struct RegisterFile saved_;

    };

}
#endif
